import { IViewComponentProps } from "@/Factory";
import { ISession, ISessionItem, local_chat_mgr_map, LocalChatMgr, remote_chat_mgr_map, RemoteChatMgr } from "@/mgr";
import { Paths } from "@/paths";
import { ArrowDownOutlined } from "@ant-design/icons";
import { Button, Flex, Image, Typography } from "antd";
import { HTMLAttributes, useEffect, useMemo, useRef, useState } from "react";
import { FlexHeader, ListEmpty } from "../_BaseView/FlexRoot";
import { Chat } from "../Chat";
import styles from "./styles.module.scss";
import { IRawMsgContent_Image } from "@/chatlog_types/IRawMsgContents";
import { useImmer } from "use-immer";
import { useLocation } from "react-router";
import { Toast } from "@/hooks/Providers";
import QueryString from "qs";

export interface IChatViewProps extends HTMLAttributes<HTMLDivElement>, IViewComponentProps<ISessionItem> {

}
const mgr_map_map: { [x in string]?: Map<string, RemoteChatMgr | LocalChatMgr> } = {
  [Paths.All.RemoteChat]: remote_chat_mgr_map,
  [Paths.All.LocalChat]: local_chat_mgr_map,
}
const mgr_cls_map: { [x in string]?: typeof RemoteChatMgr | typeof LocalChatMgr } = {
  [Paths.All.RemoteChat]: RemoteChatMgr,
  [Paths.All.LocalChat]: LocalChatMgr,
}
const mgr_kind_map: { [x in string]?: string } = {
  [Paths.All.RemoteChat]: Paths.All.RemoteChat,
  [Paths.All.LocalChat]: Paths.All.LocalChat,
}
export default function ChatView(props: IChatViewProps) {
  const { info, actived, ws_slot, onScroll, ..._p } = props
  const location = useLocation()
  const { account, userName } = useMemo(() => QueryString.parse(location.search.substring(1)), [location])

  const [toast] = Toast.use();
  const ref_ele_msg_list_view = useRef<HTMLDivElement | null>(null)
  const ref_chat_mgr = useRef<LocalChatMgr | null>(null)

  const kind = info?.kind ?? mgr_kind_map[location.pathname];
  const session: ISession = useMemo(() => {
    return info?.data ?? {
      account: '' + account,
      userName: '' + userName,
    }
  }, [info?.data, account, userName])

  const [message_count, set_message_count] = useState(0);
  const [date_range_text, set_date_range_text] = useState('')
  const [images, set_images] = useImmer({
    open: false,
    urls: [] as string[],
    current: -1,
  })
  useEffect(() => {
    if (!kind || !(kind in mgr_kind_map)) {
      toast.error(`[ChatView] kind got ${kind}, should be one of ${JSON.stringify(Object.keys(mgr_kind_map))}`)
      return;
    }
    if (!session) {
      toast.error(`[ChatView] session got ${session}`)
      return;
    }
    const ele = ref_ele_msg_list_view.current;
    if (!ele) {
      toast.error(`[ChatView] msg_list_view got ${ele}, should not happen!`)
      return;
    }
    const mgr_map = mgr_map_map[kind]
    const mgr_cls = mgr_cls_map[kind];
    if (!mgr_map || !mgr_cls) return;

    const { account, userName: talker } = session
    const mgr_key = `${account}#${talker}`

    let mgr = mgr_map.get(mgr_key)
    if (!mgr)
      mgr_map.set(mgr_key, mgr = ref_chat_mgr.current = new mgr_cls(session))

    mgr.listview.nameVisible = true;
    mgr.listview.onClickImg = async (msg) => {
      const urls: string[] = []
      let idx = 0;
      for (const other of mgr.listview.messages) {
        if (other.type !== Chat.MessageType.img) continue;
        if (other.id === msg.id) idx = urls.length
        const contents = other.raw?.contents as IRawMsgContent_Image;
        if (contents.img_url) urls.push(contents.img_url) // 远端图片
        else urls.push(other.content)
      }
      set_images({ open: true, urls, current: idx })

      let changed = false;
      for (let i = 0; i < urls.length; i++) {
        const url = urls[i];
        if (!url.endsWith('_t.dat')) continue

        // 原图
        const h_url = url.replace(/_t\.dat$/, '_h.dat')
        const h_ok = await isImageValid(h_url).then(() => true).catch(e => false)
        if (h_ok) { urls[i] = h_url; changed = true; continue; }

        // 大图
        const s_url = url.replace(/_t\.dat$/, '.dat')
        const s_ok = await isImageValid(s_url).then(() => true).catch(e => false)
        if (s_ok) { urls[i] = s_url; changed = true; continue; }
      }
      if (changed) set_images(o => { o.urls = [...urls] })
    }
    mgr.listview.headClickable = false;
    mgr.set_parent(ele)
    const c = mgr.callbacks.add({
      on_changed: (mgr) => {
        set_message_count(mgr.messages_length)
      },
      on_date_range_changed(_0, start_date, end_date) {
        const start_date_text = start_date.format('YYYY-MM-DD');
        const end_date_text = end_date.format('YYYY-MM-DD');
        set_date_range_text(`日期范围: ${start_date_text} ~ ${end_date_text}`)
      },
    })
    const start_date_text = mgr.start_date.format('YYYY-MM-DD');
    const end_date_text = mgr.end_date.format('YYYY-MM-DD');
    set_date_range_text(`日期范围: ${start_date_text} ~ ${end_date_text}`)
    mgr.start()
    return () => {
      mgr.set_parent(void 0)
      mgr.reset()
      c()
    }
  }, [kind, session, LocalChatMgr, RemoteChatMgr])
  const [is_reach_bottom, set_is_reach_bottom] = useState(true);
  return (
    <Flex {..._p} className={styles.chat_view_root} vertical align='stretch'>
      <FlexHeader>
        <Typography.Text type='secondary'>
          {date_range_text}
        </Typography.Text>
        <Typography.Text type='secondary' >
          已加载数量 {message_count}
        </Typography.Text>
      </FlexHeader>
      <Image.PreviewGroup
        items={images.urls}
        preview={{
          visible: images.open,
          current: images.current,
          onVisibleChange: () => set_images(o => { o.open = false }),
          onChange: c => set_images(o => { o.current = c }),
        }} />
      <ListEmpty show={!message_count} description='暂无消息' />
      <div ref={ref_ele_msg_list_view} className={styles.chat_view} onScroll={(e) => {
        const ele = e.target as HTMLElement;
        set_is_reach_bottom(!(ele.scrollHeight - ele.clientHeight - ele.scrollTop))
      }} />
      {
        is_reach_bottom ? null :
          <Button
            style={{ position: 'absolute', left: '50%', bottom: 30, zIndex: 1 }}
            shape='circle'
            icon={<ArrowDownOutlined />}
            type='dashed'
            onClick={() => {
              const sv = ref_ele_msg_list_view.current;
              if (!sv) return;
              sv.scrollTo({ top: sv.scrollHeight, behavior: 'smooth' })
            }} />
      }
    </Flex >
  )
}

function isImageValid(url: string): Promise<void> {
  return new Promise((resolve, reject) => {
    const img = document.createElement('img');
    img.onload = () => resolve();
    img.onerror = (e) => reject(e); // 图片无效
    img.src = url;
  })
}